package com.zp.service.impl;

import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zp.domain.entity.Picture;
import com.zp.domain.entity.Space;
import com.zp.domain.entity.User;
import com.zp.domain.request.space.analyze.*;
import com.zp.domain.response.*;
import com.zp.enums.ErrorCode;
import com.zp.exception.BusinessException;
import com.zp.mapper.SpaceMapper;
import com.zp.service.PictureService;
import com.zp.service.SpaceAnalyzeService;
import com.zp.service.SpaceService;
import com.zp.service.UserService;
import com.zp.utils.ThrowUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


@Service
@RequiredArgsConstructor
public class SpaceAnalyzeServiceImpl extends ServiceImpl<SpaceMapper, Space> implements SpaceAnalyzeService {
    private final UserService userService;
    private final PictureService pictureService;
    private final SpaceService spaceService;

    /**
     * 空间分析权限校验
     *
     * @param request   空间分析请求参数
     * @param loginUser 登录用户
     */
    private void checkSpaceAuth(SpaceAnalyzeRequest request, User loginUser) {
        ThrowUtils.throwIf(loginUser == null, ErrorCode.NOT_LOGIN_ERROR);
        Long spaceId = request.getSpaceId();
        boolean queryPublic = request.isQueryPublic();
        boolean queryAll = request.isQueryAll();
        if (queryAll || queryPublic) {
            // 需要管理员权限
            ThrowUtils.throwIf(!userService.isAdmin(loginUser), ErrorCode.NO_AUTH_ERROR);
        } else {
            if (spaceId != null) {
                // 仅空间创建人或管理员可访问
                Space space = spaceService.getById(spaceId);
                ThrowUtils.throwIf(space == null, ErrorCode.NOT_FOUND_ERROR, "空间不存在");
                ThrowUtils.throwIf(!loginUser.getId().equals(space.getUserId()) && !userService.isAdmin(loginUser),
                        ErrorCode.NO_AUTH_ERROR, "无权限操作该空间");
            }
        }
    }

    /**
     * 根据查询条件不同进行封装
     *
     * @param request 空间分析请求参数
     * @param wrapper 查询条件
     */
    private void fillAnalyzeQueryWrapper(SpaceAnalyzeRequest request, QueryWrapper<Picture> wrapper) {
        if (request.isQueryAll()) {
            // 分析全部空间, 无查询条件
            return;
        }
        if (request.isQueryPublic()) {
            // 查询公共图库
            wrapper.isNull("space_id");
            return;
        }
        if (request.getSpaceId() != null) {
            // 查询私人图库
            wrapper.eq("space_id", request.getSpaceId());
            return;
        }
        throw new BusinessException(ErrorCode.OPERATION_ERROR);
    }

    /**
     * 空间大小使用分析
     *
     * @param request   请求参数
     * @param loginUser 登录用户
     * @return 响应结果
     */
    @Override
    public SpaceUsageAnalyzeResponse getSpaceUsageAnalyze(SpaceUsageAnalyzeRequest request, User loginUser) {
        // 1. 参数校验
        ThrowUtils.throwIf(request == null, ErrorCode.PARAMS_ERROR);
        ThrowUtils.throwIf(loginUser == null, ErrorCode.NOT_LOGIN_ERROR);
        boolean queryPublic = request.isQueryPublic();
        boolean queryAll = request.isQueryAll();
        if (queryAll || queryPublic) {
            // 全空间分析或公共图库分析
            // 1. 权限校验
            this.checkSpaceAuth(request, loginUser);
            // 2. 设置查询条件, 只查询指定的字段
            QueryWrapper<Picture> wrapper = new QueryWrapper<>();
            wrapper.select("pic_size");
            this.fillAnalyzeQueryWrapper(request, wrapper);
            // 3. 执行查询
            // 列表中其实就一个 pic_size 字段
            List<Object> picSize = pictureService.getBaseMapper().selectObjs(wrapper);
            // 4. 数据处理
            // 统计已使用的大小
            long usedSize = picSize.stream().mapToLong(i -> (Long) i).sum();
            // 统计已使用的数量
            long usedCount = picSize.size();
            // 封装返回结果
            SpaceUsageAnalyzeResponse response = new SpaceUsageAnalyzeResponse();
            response.setUsedSize(usedSize);
            response.setUsedCount(usedCount);
            // 全空间 或 公共图库 容量无上限
            response.setMaxSize(null);
            response.setMaxCount(null);
            response.setSizeUsageRatio(null);
            response.setCountUsageRatio(null);
            return response;
        } else {
            // 个人空间分析
            Long spaceId = request.getSpaceId();
            ThrowUtils.throwIf(spaceId == null, ErrorCode.PARAMS_ERROR);
            Space space = spaceService.getById(spaceId);
            ThrowUtils.throwIf(space == null, ErrorCode.NOT_FOUND_ERROR, "空间不存在");
            // 权限校验
            this.checkSpaceAuth(request, loginUser);
            // 封转返回结果
            SpaceUsageAnalyzeResponse response = new SpaceUsageAnalyzeResponse();
            response.setUsedSize(space.getTotalSize());
            response.setMaxSize(space.getMaxSize());
            response.setUsedCount(space.getTotalCount());
            response.setMaxCount(space.getMaxCount());
            double sizeRatio = NumberUtil.round(space.getTotalSize() * 100.0 / space.getMaxSize(), 2).doubleValue();
            double countRatio = NumberUtil.round(space.getTotalCount() * 100.0 / space.getMaxCount(), 2).doubleValue();
            response.setSizeUsageRatio(sizeRatio);
            response.setCountUsageRatio(countRatio);
            return response;
        }
    }

    /**
     * 空间图片分类分析
     *
     * @param request   请求参数
     * @param loginUser 登录用户
     * @return 响应结果
     */
    @Override
    public List<SpaceCategoryAnalyzeResponse> getSpaceCategoryAnalyze(SpaceCategoryAnalyzeRequest request, User loginUser) {
        // 校验参数
        ThrowUtils.throwIf(request == null, ErrorCode.PARAMS_ERROR);
        ThrowUtils.throwIf(loginUser == null, ErrorCode.NOT_LOGIN_ERROR);
        // 检查权限
        this.checkSpaceAuth(request, loginUser);
        // 构造查询条件
        QueryWrapper<Picture> wrapper = new QueryWrapper<>();
        this.fillAnalyzeQueryWrapper(request, wrapper);
        wrapper.select("category", "count(*) as count", "sum(pic_size) as totalSize").groupBy("category");
        return pictureService.getBaseMapper().selectMaps(wrapper)
                .stream()
                .map(result -> {
                    String category = result.get("category") != null ? result.get("category").toString() : "未分类";
                    long count = Long.parseLong(result.get("count").toString());
                    long totalSize = Long.parseLong(result.get("totalSize").toString());
                    return new SpaceCategoryAnalyzeResponse(category, count, totalSize);
                }).collect(Collectors.toList());
    }

    /**
     * 获取空间图片标签分析
     *
     * @param request   获取空间图片标签分析请求
     * @param loginUser 登录用户
     * @return 图片标签分析结果
     */
    @Override
    public List<SpaceTagAnalyzeResponse> getSpaceTagAnalyze(SpaceTagAnalyzeRequest request, User loginUser) {
        // 校验参数
        ThrowUtils.throwIf(request == null, ErrorCode.PARAMS_ERROR);
        ThrowUtils.throwIf(loginUser == null, ErrorCode.NOT_LOGIN_ERROR);
        // 检查权限
        this.checkSpaceAuth(request, loginUser);
        // 封装查询条件
        QueryWrapper<Picture> wrapper = new QueryWrapper<>();
        this.fillAnalyzeQueryWrapper(request, wrapper);
        wrapper.select("tags");
        // 查询所有符合条件的标签
        List<String> tagsList = pictureService.getBaseMapper().selectObjs(wrapper)
                .stream()
                .filter(ObjUtil::isNotNull)
                .map(Object::toString)
                .collect(Collectors.toList());
        // 2. 合并所有标签并统计使用次数(k, v : 标签名, 使用次数)
        // 扁平化: ["java", "python"], ["java", "php"] ===> ["java", "python", "php"]
        Map<String, Long> tagsMap = tagsList.stream()
                .flatMap(tag -> JSONUtil.toList(tag, String.class).stream())
                .collect(Collectors.groupingBy(tag -> tag, Collectors.counting()));
        // 3. 转换为响应对象, 按使用次数降序排序
        return tagsMap.entrySet().stream()
                .sorted(Comparator.<Map.Entry<String, Long>>comparingLong(Map.Entry::getValue).reversed())
                .map(entry -> new SpaceTagAnalyzeResponse(entry.getKey(), entry.getValue()))
                .collect(Collectors.toList());
    }

    /**
     * 空间内图片大小分析
     *
     * @param request   图片大小分析请求
     * @param loginUser 当前登录用户
     * @return 图片大小分析结果
     */
    @Override
    public List<SpaceSizeAnalyzeResponse> getSpaceSizeAnalyze(SpaceSizeAnalyzeRequest request, User loginUser) {
        // 校验参数
        ThrowUtils.throwIf(request == null, ErrorCode.PARAMS_ERROR);
        ThrowUtils.throwIf(loginUser == null, ErrorCode.NOT_LOGIN_ERROR);
        // 检查权限
        this.checkSpaceAuth(request, loginUser);
        // 构造查询条件
        QueryWrapper<Picture> wrapper = new QueryWrapper<>();
        wrapper.select("pic_size");
        this.fillAnalyzeQueryWrapper(request, wrapper);
        List<Long> picSizeList = pictureService.getBaseMapper().selectObjs(wrapper)
                .stream()
                .map(obj -> ((Number) obj).longValue())
                .collect(Collectors.toList());
        // 定义有序的图片范围
        Map<String, Long> sizeRange = new LinkedHashMap<>();
        sizeRange.put("<100KB", picSizeList.stream().filter(i -> i < 100 * 1024).count());
        sizeRange.put("100KB - 500KB", picSizeList.stream().filter(i -> i > 100 * 1024 && i < 500 * 1024).count());
        sizeRange.put("500KB - 1MB", picSizeList.stream().filter(i -> i > 500 * 1024 && i < 1024 * 1024).count());
        sizeRange.put(">1MB", picSizeList.stream().filter(i -> i > 1024 * 1024).count());
        return sizeRange.entrySet().stream()
                .map(entry -> new SpaceSizeAnalyzeResponse(entry.getKey(), entry.getValue()))
                .collect(Collectors.toList());
    }

    /**
     * 用户上传行为分析
     *
     * @param request   获取空间用户分析请求
     * @param loginUser 登录用户
     * @return 用户分析结果
     */
    @Override
    public List<SpaceUserAnalyzeResponse> getSpaceUserAnalyze(SpaceUserAnalyzeRequest request, User loginUser) {
        // 校验参数
        ThrowUtils.throwIf(request == null, ErrorCode.PARAMS_ERROR);
        ThrowUtils.throwIf(loginUser == null, ErrorCode.NOT_LOGIN_ERROR);
        // 检查权限
        this.checkSpaceAuth(request, loginUser);
        // 构造查询条件
        QueryWrapper<Picture> wrapper = new QueryWrapper<>();
        Long userId = request.getUserId();
        wrapper.eq(ObjUtil.isNotEmpty(userId), "user_id", userId);
        this.fillAnalyzeQueryWrapper(request, wrapper);
        String dimension = request.getTimeDimension();
        switch (dimension) {
            case "day":
                wrapper.select("DATE_FORMAT(create_time, '%Y-%m-%d') as period", "count(*) as count");
                break;
            case "week":
                wrapper.select("YEARWEEK(create_time) as period", "count(*) as count");
                break;
            case "month":
                wrapper.select("DATE_FORMAT(create_time, '%Y-%m') as period", "count(*) as count");
                break;
            default:
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "时间维度错误");
        }
        // 分组并排序
        wrapper.groupBy("period").orderByDesc("period");
        // 查询结果并转换
        return pictureService.getBaseMapper().selectMaps(wrapper)
                .stream()
                .map(result -> {
                    String period = result.get("period").toString();
                    long count = ((Number) result.get("count")).longValue();
                    return new SpaceUserAnalyzeResponse(period, count);
                })
                .collect(Collectors.toList());
    }

    /**
     * 空间使用排行分析
     *
     * @param request   获取空间使用排行请求
     * @param loginUser 登录用户
     * @return 空间排名
     */
    @Override
    public List<Space> getSpaceRankAnalyze(SpaceRankAnalyzeRequest request, User loginUser) {
        // 校验参数
        ThrowUtils.throwIf(request == null, ErrorCode.PARAMS_ERROR);
        ThrowUtils.throwIf(loginUser == null, ErrorCode.NOT_LOGIN_ERROR);
        // 仅管理员使用
        ThrowUtils.throwIf(!userService.isAdmin(loginUser), ErrorCode.NO_AUTH_ERROR);
        // 构造查询条件
        QueryWrapper<Space> wrapper = new QueryWrapper<>();
        wrapper.select("id", "space_name", "total_size", "user_id")
                .orderByDesc("total_size")
                // 获取前 N 个
                .last("limit " + request.getTopN());
        // 查询结果
        return spaceService.list(wrapper);
    }
}




